package com.tanhua.dubbo.api.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.tanhua.dubbo.api.UserLikeApi;
import com.tanhua.dubbo.pojo.UserLike;
import com.tanhua.dubbo.vo.PageInfo;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

@DubboService(version = "1.0.0")
public class UserLikeApiImpl implements UserLikeApi {

    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";

    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
        //判断用户是否已经喜欢
        if (this.isLike(userId, likeUserId)) {
            return false;
        }

        //存储到redis，使用的是hash结构
        //用户1喜欢用户2 ->  大key：USER_LIKE_1  小key："2" 值："1"
        //用户1喜欢用户3 ->  大key：USER_LIKE_1  小key："3" 值："1"
        //用户3喜欢用户1 ->  大key：USER_LIKE_3  小key："1" 值："1"

        String redisKey = this.getLikeRedisKey(userId);
        String hashKey = Convert.toStr(likeUserId);
        this.redisTemplate.opsForHash().put(redisKey, hashKey, "1");

        //存储到MongoDB中
        this.saveMongoDB(userId, likeUserId, true);

        //无论对方是否在我的不喜欢列表中，直接将其删除
        this.redisTemplate.opsForHash().delete(this.getNotLikeRedisKey(userId), hashKey);

        return true;
    }

    private void saveMongoDB(Long userId, Long likeUserId, Boolean isLike) {
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("likeUserId").is(likeUserId));
        UserLike userLike = this.mongoTemplate.findOne(query, UserLike.class);

        if (ObjectUtil.isEmpty(userLike)) {
            //存储到MongoDB
            userLike = new UserLike();
            userLike.setId(ObjectId.get());
            userLike.setUserId(userId);
            userLike.setLikeUserId(likeUserId);
            userLike.setCreated(System.currentTimeMillis());
            userLike.setUpdated(userLike.getCreated());
            userLike.setIsLike(isLike);
            this.mongoTemplate.save(userLike);
        } else {
            //更新字段
            Update update = Update.update("isLike", isLike)
                    .set("updated", System.currentTimeMillis());
            this.mongoTemplate.updateFirst(query, update, UserLike.class);
        }
    }

    /**
     * 喜欢列表的大key
     *
     * @param userId
     * @return
     */
    private String getLikeRedisKey(Long userId) {
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 不喜欢列表的大key
     *
     * @param userId
     * @return
     */
    private String getNotLikeRedisKey(Long userId) {
        return NOT_LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {
        if (this.isNotLike(userId, likeUserId)) {
            return false;
        }

        //保存不喜欢到redis
        String redisKey = this.getNotLikeRedisKey(userId);
        String hashKey = Convert.toStr(likeUserId);
        this.redisTemplate.opsForHash().put(redisKey, hashKey, "1");

        //保存到mongodb
        this.saveMongoDB(userId, likeUserId, false);

        //无论用户是否在我的喜欢列表中，都将其删除
        this.redisTemplate.opsForHash().delete(this.getLikeRedisKey(userId), hashKey);

        return true;
    }

    /**
     * 是否喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isLike(Long userId, Long likeUserId) {
        String redisKey = this.getLikeRedisKey(userId);
        String hashKey = Convert.toStr(likeUserId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, hashKey);
}

    /**
     * 是否不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isNotLike(Long userId, Long likeUserId) {
        String redisKey = this.getNotLikeRedisKey(userId);
        String hashKey = Convert.toStr(likeUserId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, hashKey);
    }

    /**
     * 是否相互喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        return this.isLike(userId, likeUserId) && this.isLike(likeUserId, userId);
    }

    /**
     * 查询喜欢列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryLikeList(Long userId) {
        String redisKey = this.getLikeRedisKey(userId);
        return this.queryList(redisKey);
    }

    /**
     * 查询不喜欢列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryNotLikeList(Long userId) {
        String redisKey = this.getNotLikeRedisKey(userId);
        return this.queryList(redisKey);
    }

    private List<Long> queryList(String redisKey) {
        //获取喜欢的所有小key
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if (CollUtil.isEmpty(keys)) {
            return Collections.emptyList();
        }

        List<Long> list = new ArrayList<>();
        keys.forEach(key -> list.add(Convert.toLong(key)));
        return list;
    }

    /**
     * 相互喜欢的数量
     *
     * @return
     */
    @Override
    public Long queryMutualLikeCount(Long userId) {
        //思路：先查询我喜欢的列表，在列表中查看这些人是否也喜欢我
        List<Long> myLikeList = this.queryLikeList(userId);
        Long count = 0L;
        for (Long uid : myLikeList) {
            if (this.isLike(uid, userId)) {
                count++;
            }
        }
        return count;
    }

    /**
     * 喜欢数
     *
     * @return
     */
    @Override
    public Long queryLikeCount(Long userId) {
        String redisKey = this.getLikeRedisKey(userId);
        return this.redisTemplate.opsForHash().size(redisKey);
    }

    /**
     * 粉丝数
     *
     * @return
     */
    @Override
    public Long queryFanCount(Long userId) {
        Query query = Query.query(Criteria.where("likeUserId").is(userId)
                .and("isLike").is(true));
        return this.mongoTemplate.count(query, UserLike.class);
    }

    @Override
    public PageInfo<UserLike> queryLikeList(Long userId, Integer page, Integer pageSize) {
        //设置分页
        Integer pageResult = page - 1;
        if (pageResult < 0) {
            pageResult = 0;
        }
        PageRequest pageRequest =PageRequest.of(pageResult, pageSize ,
                Sort.by(Sort.Order.desc("updated")));
        //查询条件
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("isLike").is(true)).with(pageRequest);
        //在mongodb中查
        List<UserLike> userLikeList = this.mongoTemplate.find(query, UserLike.class);
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setRecords(userLikeList);
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        return pageInfo;
    }

    @Override
    public PageInfo<UserLike> queryMutualLikeList(Long userId, Integer page, Integer pageSize) {
        Integer pageResult = page - 1;
        if (pageResult < 0) {
            pageResult = 0;
        }
        PageRequest pageRequest = PageRequest.of(pageResult,pageSize,
                Sort.by(Sort.Order.desc("updated")));
        List<Long> myLikeList = this.queryLikeList(userId);

        //查询喜欢我的人
        Query query = Query.query(Criteria.where("userId").in(myLikeList)
                .and("likeUserId").is(userId)
        );

        List<UserLike> mutualLikeList = this.mongoTemplate.find(query, UserLike.class);
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(mutualLikeList);
        return pageInfo;
    }

    @Override
    public PageInfo<UserLike> queryFanList(Long userId, Integer page, Integer pageSize) {
        //设置分页
        Integer pageResult = page - 1;
        if (pageResult < 0) {
            pageResult = 0;
        }
        PageRequest pageRequest = PageRequest.of(pageResult,pageSize,
                Sort.by(Sort.Order.desc("updated")));
        Query query = Query.query(Criteria.where("likeUserId").is(userId)
        .and("isLike").is(true)).with(pageRequest);

        List<UserLike> userLikeList = this.mongoTemplate.find(query, UserLike.class);
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(userLikeList);
        return pageInfo;
    }
}
